#include "Configuration.hpp"
#include "Dictionary.hpp"
#include "StringSplit.hpp"

#include <fstream>
#include <sstream>

namespace se {

using CharacterList = std::shared_ptr<std::vector<std::string>>;

Dictionary::Dictionary() {
    Configuration &configuration = Singleton<Configuration>::getInstance();
    this->dictionaryInitialize(configuration["DictionaryPath"].get<std::string>(),
        configuration["IndexPath"].get<std::string>());
}

void Dictionary::dictionaryInitialize(const std::string &dictionaryFileName, const std::string &indexFileName) {
    // 反序列化字典文件
    nlohmann::json dictionaryJson(this->getJsonFromFile(dictionaryFileName));
    this->_dictionary = std::vector<std::pair<std::string, int32_t>>(dictionaryJson.begin(), dictionaryJson.end());

    // 反序列化索引文件
    nlohmann::json indexJson(this->getJsonFromFile(indexFileName));
    for (auto iterator = indexJson.begin(); iterator != indexJson.end(); ++iterator) {
        auto &set = iterator.value();
        this->_index.insert({iterator.key(), std::set<int32_t>(set.begin(), set.end())});
    }
}

std::shared_ptr<std::map<std::string, int32_t>>
Dictionary::query(const std::string &keyword) {
    // keyword的字符数组
    CharacterList keywordSplit = StringSplit::split(keyword, StringSplit::Encoding::UTF8);
    // 将keyword的字符数组去重
    // std::set<std::string> keywordSplitSet(keywordSplit->begin(), keywordSplit->end());

    std::shared_ptr<std::map<std::string, int32_t>> recommenderWords(new std::map<std::string, int32_t>());
    // 遍历keyword中的所有字符，在索引map中找到还包含该字符的所有单词
    // for (auto &item : keywordSplitSet) {
    //     for (auto index : this->_index[item]) {
    //         recommenderWords->insert(this->_dictionary[index]);
    //     }
    // }

    // return recommenderWords_optimize;

    for (auto index : this->_index[keywordSplit->front()]) {
        if (::strncmp(this->_dictionary[index].first.c_str(), keyword.c_str(), keyword.size()) == 0) {
            recommenderWords->insert(this->_dictionary[index]);
        }
    }

    return recommenderWords;
}

int32_t Dictionary::getEditDistance(const std::string &lhs, const std::string &rhs) {
    // 获取每个字符串对应的字符数组
    CharacterList left = StringSplit::split(lhs, StringSplit::Encoding::UTF8);
    CharacterList right = StringSplit::split(rhs, StringSplit::Encoding::UTF8);
    
    // 建立动态规划所需的二维数组，计算最小编辑距离
    std::vector<std::vector<int32_t>> dynamicPrograming;
    for (size_t i = 0; i <= left->size(); i++) {
        dynamicPrograming.push_back(std::vector<int32_t>(right->size() + 1));
    }

    for (size_t i = 0; i < dynamicPrograming.size(); ++i) {
        for (size_t j = 0; j < dynamicPrograming[0].size(); ++j) {
            if (i == 0 && j == 0) { dynamicPrograming[i][j] = 0; }
            else if (i == 0 && j > 0) { dynamicPrograming[i][j] = j; }
            else if (i > 0 && j == 0) { dynamicPrograming[i][j] = i; }
            else {
                dynamicPrograming[i][j] = std::min(
                    dynamicPrograming[i - 1][j] + 1,
                    std::min(
                        dynamicPrograming[i][j - 1] + 1,
                        dynamicPrograming[i - 1][j - 1] + ((*left)[i - 1] == (*right)[j - 1] ? 0 : 1)
                    )
                );
            }
        }
    }
    return dynamicPrograming.back().back();
}


nlohmann::json Dictionary::getJsonFromFile(const std::string &fileName) {
    std::ifstream inputStream(fileName);
    nlohmann::json tempJson;
    inputStream >> tempJson;
    inputStream.close();
    return tempJson;
}

std::string Dictionary::toString() const {
    std::ostringstream stringStream;

    for (auto &element : this->_dictionary) {
        stringStream << element.first << " : " << element.second << std::endl;
    }

    for (auto &element : this->_index) {
        stringStream << element.first << " : ";
        for (auto &item : element.second) {
            stringStream << item << " ";
        }
        stringStream << std::endl;
    }

    return stringStream.str();
}

}  // namespace se
